import math
import os
import socket
from pynput import keyboard
import subprocess
import sys,base64
import threading
import logging
from time import sleep
from datetime import datetime
from threading import Thread


logger=logging.getLogger("running.log")
logger.setLevel(logging.DEBUG)

fh=logging.FileHandler("client_server_run.log",mode="a")
fh.setLevel(logging.DEBUG)

formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)


def net_work_connect_if():
    ret = subprocess.run("ping baidu.com -n 1", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    # print(ret.returncode)
    return True if ret.returncode == 0 else False

def on_press(key):
    try:
        try:
            inde=parament.press_code.index(key.char)
            if parament.press_state[inde]==0:
                parament.press_state[inde]=1
                # print(2)
            elif parament.press_state[inde]==1:
                parament.press_state[inde]=1
                # print(parament.press_code[inde])
            else:
                # print(3)
                parament.press_state[inde]=0
        except Exception as e:
            # print(e.args)
            parament.press_code.append(key.char)
            parament.press_state.append(0)
            # print(parament.press_code)
            # print(parament.press_state)
    except AttributeError:
        # print(f'special key {key} pressed')
        pass
def on_release(key):
    # print(f'{key} released')
    try:
        parament.last_release=key.char
        parament.press_state.remove(parament.press_state.index(key.char))
        parament.press_code.remove(parament.press_code.index(key.char))
    except:
        pass
    if key == keyboard.Key.esc:
        return False

# 创建监听器对象
# @func_set_timeout(1)
# def press_thread():
#     with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
#         listener.start()



def log_print(data):
    logger.info(data)

def datas_creat(head,msg,size):
    send_report=b''
    Headsize=128
    Lengthsize=128
    Length=b''
    Msgs=b''
    Head=b"Head:"+str(head).encode()
    Head+=b" "*(Headsize-len(Head))
    # print(Head)
    if type(msg)==type(b'111'):
        Lengths = str(len(msg))
        Length = b"Length:" + Lengths.encode()
        Length += b" " * (Lengthsize - len(Length))
        # print(Length)
        Msgs = b"Msgs:" + msg
    elif type(msg)==type('  '):
        Lengths =str(len(msg.encode()))
        Length=b"Length:"+Lengths.encode()
        Length+=b" "*(Lengthsize-len(Length))
        # print(Length)
        Msgs=b"Msgs:"+msg.encode()
    # print(Msgs)
    send_report=Head+Length+Msgs
    # print(send_report)
    released_length=size-len(send_report)
    Tail=b'Tail:'+(released_length-5)*b" "
    send_report=send_report+Tail
    return send_report

def report_cut(datas_report):
    # print(datas_report)
    report_list=list()
    Head_inde_s=0
    Head_inde_e=Head_inde_s+4
    Length_inde_s=128
    Length_inde_e=Length_inde_s+6
    Msgs_inde_s=256+5
    Msgs_inde_e=Msgs_inde_s
    Head_byte=datas_report[Head_inde_s:Head_inde_e]
    Head_num=datas_report[Head_inde_e+1:Length_inde_s]
    Length_byte=datas_report[Length_inde_s:Length_inde_e]
    Length_num=datas_report[Length_inde_e+1:Msgs_inde_s-5]
    # print(Head_byte,Head_num,Length_byte,Length_num)
    if Head_byte==b'Head' and Length_byte==b'Length':
        Head_str=int(Head_num.decode())
        Length_num=int(Length_num.decode())
        Msgs_inde_e+=int(Length_num)
        # print(Length_num,Msgs_inde_s,Msgs_inde_e)
        Msgs_str=datas_report[Msgs_inde_s:Msgs_inde_e]
        if type(Msgs_str)==type(" "):
            Msgs_str=Msgs_str
        elif type(Msgs_str)==type(b" "):
            Msgs_str=Msgs_str.decode()
        Tail_inde_s=Msgs_inde_e
        Tail_inde_e=Tail_inde_s+4
        Tail_byte=datas_report[Tail_inde_s:Tail_inde_e]
        Tail_str=datas_report[Tail_inde_e+1:8192]
        # print(Msgs_str,Tail_byte,Tail_str)
        if Tail_byte==b'Tail':
            Tail_str=Tail_str.decode()
            report_list.append(Head_str)
            report_list.append(Length_num)
            report_list.append(Msgs_str)
            report_list.append(Tail_str)
        else:
            report_list=None
    else:
        report_list=None
    return (report_list)

def split_file(_base64_str,_len):
    _base64_str_list = [_base64_str[i:i + _len] for i in range(0, len(_base64_str), _len)]
    # print(_base64_str_list)
    return _base64_str_list


class Parament():
    def __init__(self):
        self.conn_dect=0
        self.conn_dect_flag=False
        self.server_if=True
        self.server_login_if=False
        self.conn_state=False
        self.get_data=None
        self.msg_id=None
        self.recv_size_set=8192
        self.running_sleep_time=0.005
        self.ip_pool=list()
        self.text_in=None
        self.press_state=list()
        self.total_pr=0
        self.press_code=list()
        self.file_totalsize=0
        self.file_recv_size=0
        self.pack_count=0
        self.file_operate=None
        self.last_release=None
        self.WAIT_STATE="WAIT STATE"
        self.FILE_TRANSMIT_STATE="TRANSMIT STATE"
        self.state = self.WAIT_STATE
        self.send_list=list()
        self.recv_list=list()

    def inits(self):
        self.server_if = True
        self.server_login_if = False
        self.conn_state = False
        self.get_data = None
        self.msg_id = None
        self.recv_size_set = 8192
        self.running_sleep_time = 0.005
        self.ip_pool = list()
        self.text_in = None
        self.press_state = list()
        self.press_code = list()
        self.file_totalsize = 0
        self.file_recv_size = 0
        self.pack_count = 0
        self.file_operate = None
        self.last_release = None
        self.WAIT_STATE = "WAIT STATE"
        self.FILE_TRANSMIT_STATE = "TRANSMIT STATE"
        self.state = self.WAIT_STATE

class Datas_send_struct:
    def __init__(self,dp):
        self.datas_report=dp

class Datas_recv_struct:
    def __init__(self,dp):
        self.datas_report=dp
        self.recv_id = report_cut(dp)[0]
        self.length = report_cut(dp)[1]
        self.msg = report_cut(dp)[2]
        self.tail = report_cut(dp)[3]

def Send_Data_struct_creat(id,msg,root_if=False):
    sed_rp=datas_creat(id,msg,parament.recv_size_set)
    data_struct=Datas_send_struct(sed_rp)
    parament.send_list.append(data_struct)

def Recv_Data_struct_creat(msg):
    rec_struct=Datas_recv_struct(msg)
    parament.recv_list.append(rec_struct)

parament=Parament()




class Client():
    def __init__(self):
        # self.host = '100.108.189.24'
        self.host='localhost'
        # self.host='43.134.99.154'
        self.port = 8878
        self.client = socket.socket()
        self.client.settimeout(0.00)
        self.id=None
        self.send_id=None
        self.inits_flag=False
    def inits(self):
        try:
            self.client.connect((self.host,self.port))
            print("connected to {}:{}".format(self.host,self.port))
            parament.conn_state=True
            self.client.setblocking(False)
            # print(1)
        except Exception as e:
            # print(2)
            # print(e)
            # self.int_past_time=runmain.timess
            if parament.total_pr<10:
                print("1 {}".format(e.args[0]))
                print("unable to connected to {}:{}".format(self.host,self.port))
                parament.total_pr += 1
                parament.conn_dect_flag = True
                parament.conn_dect = 50
            parament.conn_state=False
            sleep(0.5)
            if e.args[0]==10056:
                if parament.total_pr < 10:
                    print("connected to {}:{}".format(self.host, self.port))
                parament.conn_state = True
                self.client.setblocking(False)
                parament.total_pr+=1
                parament.conn_dect_flag=True
                parament.conn_dect=50
            elif e.args[0]==10054:
                parament.conn_state=False
    def get_time(self):
        return datetime.timestamp(datetime.now())
    def start(self):
        try:
            if self.inits_flag == False:
                self.id=int(self.get_time())
                self.client.setblocking(False)
                self.inits_flag=True
            sleep(parament.running_sleep_time)
        except Exception as e:
            print("2 {}".format(e.args[0]))
            # pass
        self.recv_data()
        if parament.server_if:
            if not parament.server_login_if:
                Send_Data_struct_creat(self.id,"rot admin 52477332",False)
        else:
            if parament.last_release=='i':
                # tcflush(sys.stdin,TCIFLUSH)
                parament.text_in=input("\ninput commnad:")
                parament.last_release=None
                Send_Data_struct_creat(self.id,parament.text_in,False)
        self.send_list_conf()
        self.recv_list_conf()
        self.dect_conn()

    def dect_conn(self):
        if parament.conn_dect_flag:
            if parament.conn_dect>-5:
                parament.conn_dect-=1
            if parament.conn_dect<0:
                parament.conn_state=False
                parament.server_login_if=False
                parament.conn_dect_flag=False

    def send_list_conf(self):
        if len(parament.send_list)>0:
            operate=parament.send_list[0]
            self.data_send(operate.datas_report)
            parament.send_list.remove(operate)

    def recv_list_conf(self):
        if len(parament.recv_list)>0:
            operate=parament.recv_list[0]
            print(operate.datas_report)
            self.msg_conf(operate)
            parament.recv_list.remove(operate)

    def msg_conf(self,rd_struct):
        cmd=rd_struct.msg[0:3]
        if cmd == "rot" and parament.server_login_if == False:
            mess = rd_struct.msg[4:len(rd_struct.msg)]
            # print(mess)
            if mess == "login success":
                parament.server_login_if = True
                print("login success")
            else:
                print(rd_struct.datas_report)
        elif parament.server_login_if:
            Send_Data_struct_creat(rd_struct.recv_id,rd_struct.msg,True)
        else:
            print(rd_struct.msg)
        # print(msg)
        # cmd=msg[0:3]
        # # print(cmd)

        # elif cmd=="fss":
        #     if parament.state==parament.WAIT_STATE:
        #         try:
        #             parament.file_totalsize=int(msg.split(' ')[1])
        #             parament.file_recv_size=0
        #             parament.file_operate=open(msg.split(' ')[2],"wb")
        #             parament.state=parament.FILE_TRANSMIT_STATE
        #         except:
        #             # print(msg,parament.pack_count)
        #             self.data_send("file send to server error")
        #     elif parament.state==parament.FILE_TRANSMIT_STATE:
        #         parament.file_recv_size+=parament.recv_size_set
        #         parament.file_operate.write(bytes(msg[4:len(msg)],encoding='utf-8'))
        #         print(parament.pack_count,parament.file_recv_size,parament.file_totalsize)
        #         parament.pack_count+=1
        #         if parament.file_totalsize==parament.file_recv_size:
        #             parament.file_operate.close()
        #             parament.state=parament.WAIT_STATE
        #             parament.pack_count=0
        #
        # else:
        #     print("recv from limdzh's server:{}".format(msg))
        #     self.data_send("recv from limdzh's server:{}".format(msg))
        # self.send_id=parament.get_data[0]
        # parament.get_data=None
    def recv_data(self):
        try:
            msg=self.client.recv(parament.recv_size_set)
            if report_cut(msg)!=None:
                Recv_Data_struct_creat(msg)
        except BlockingIOError:
            if parament.conn_dect <100:
                parament.conn_dect+=1
            return None
        except:
            parament.conn_state=False
            parament.server_login_if=False
            parament.conn_dect_flag=False
            print("connection reset error")
        # except Exception as e:
        #     print("3 {}".format(e.args[0]))
    def data_send(self,msg):
        if msg:
            try:
                self.client.send(msg)
            except Exception as e:
                print("4 {}".format(e.args[0]))
    def running(self):
        while True:
            if not parament.conn_state:
                self.inits()
            else:
                self.start()
            if net_work_connect_if()==False:
                break


if __name__ == '__main__':
    while True:
        if net_work_connect_if()==False:
            pass
            # print(1)
        else:
            client=Client()
            while True:
                # try:
                if net_work_connect_if()==False:
                    break
                if not parament.server_if:
                    listener = keyboard.Listener(on_press=on_press, on_release=on_release)
                    listener.start()
                client.running()
